#pragma once

#include <algorithm>
#include <memory>
#include <string>
#include <unordered_map>


#include "es.h"
#include "user_action.pb.h"
#include "problem.pb.h"

namespace lyt{


    #define es_problem_index                "oj_problem_index"

    #define es_problem_id_key               "problem_id"
    #define es_problem_title_key            "problem_title"
    #define es_problem_difficulty_key       "difficulty"
    #define es_problem_description_key      "description"
    #define es_problem_tags_key             "tags"
    #define es_problem_testcasehint_key     "testcasehint"

    class ProblemInfo{
    public:
        int problem_id;
        std::string problem_title;
        int difficulty;
        std::string description;
        std::string tags;
        std::string testcasehint;
        
    };

    class EsProblemData{
    public:
        using ptr = std::shared_ptr<EsProblemData>;
        EsProblemData(const lyt::esclient::ptr& client)
            :_client(client)
        {}
        
        //  message KafkaCreateproblemInfo{
        //      string problem_id = 1;
        //      string title = 2;
        //      string date = 3;
        //      string user_id = 4;
        //      string preview = 5;
        // }
        bool index() {
            return lyt::index(_client)
                .add_integer_field(es_problem_id_key)
                .add_text_field(es_problem_title_key)
                .add_keyword_field(es_problem_difficulty_key)
                .add_text_field(es_problem_description_key)
                .add_keyword_field(es_problem_tags_key)
                .add_text_field(es_problem_testcasehint_key)
                .run(es_problem_index);
        }

        bool insert(const ProblemInfo& info) {
            return lyt::insert(_client)
                .set_value(es_problem_id_key,info.problem_id)
                .set_value(es_problem_title_key,info.problem_title)
                .set_value(es_problem_difficulty_key,info.difficulty)
                .set_value(es_problem_description_key,info.description)
                .set_value(es_problem_tags_key,info.tags)
                .set_value(es_problem_testcasehint_key,info.testcasehint)
                .run(es_problem_index, std::to_string(info.problem_id));
        }
        bool remove(int id) {
            return _client->remove_data(es_problem_index, std::to_string(id));
        }
        // 通过 向量查找
        bool search(const std::string& key,std::vector<ProblemInfo>& ps) {
            auto ret =  lyt::search(_client)
                .add_should_terms_keyword(es_problem_id_key, {key})
                .add_should_match(es_problem_title_key, key)
                .run(es_problem_index);
            ps.clear();
            int rs = ret.first.size();
            for (int i = 0; i < rs; i++) {
                ProblemInfo info;
                info.problem_id = ret.first[i]["_source"][es_problem_id_key].asInt();
                info.problem_title = ret.first[i]["_source"][es_problem_title_key].asString();
                info.difficulty = ret.first[i]["_source"][es_problem_difficulty_key].asInt();
                info.description = ret.first[i]["_source"][es_problem_description_key].asString();
                info.tags = ret.first[i]["_source"][es_problem_tags_key].asString();
                info.testcasehint = ret.first[i]["_source"][es_problem_testcasehint_key].asString();
                ps.push_back(std::move(info));
            }
            return true;
        }
        esclient::ptr getclient(){
            return _client;
        }
        
    private:
        esclient::ptr _client;
    };
}